//
// Created by antler on 2018/12/15.
//

#include "XMod.h"

#include "GlobalMacros.h"

#include "luaext/screen/Screen.h"

const char *XMod::PLATFORM_IOS = "iOS";
const char *XMod::PLATFORM_ANDROID = "Android";

const char *XMod::EXPECTED_ORIENTATION = "expected_orientation";
const char *XMod::SCREENCAP_POLICY = "screencap_policy";
const char *XMod::SCREENCAP_KEEP = "screencap_keep";

XMod *XMod::g_XMod = nullptr;

XMod *XMod::getInstance() {
    if (!g_XMod) {
        g_XMod = new XMod();
    }
    return g_XMod;
}

void XMod::releaseInstance() {
    SAFE_DELETE(g_XMod);
}

XMod::XMod() {

}

XMod::~XMod() {

}

const char *XMod::getPlatform() {
    return PLATFORM_ANDROID;
}

int XMod::getProductCode() {
    return PRODUCT_CODE_DEV;
}

const char *XMod::getProductName() {
    static std::map<int, const char *> VERSION2NAME = {
            {PRODUCT_CODE_DEV,    "DEV"},
            {PRODUCT_CODE_XXZS,   "XXZS"},
            {PRODUCT_CODE_IPA,    "IPA"},
            {PRODUCT_CODE_KUWAN,  "KUWAN"},
            {PRODUCT_CODE_SPIRIT, "SPIRIT"},
    };
    return VERSION2NAME[getProductCode()];
}

int XMod::getVersionCode() {
    return VERSION_CODE;
}

const char *XMod::getVersionName() {
    return VERSION_NAME;
}

bool XMod::getConfig_Bool(const std::string &key, bool def) {
    if (key == SCREENCAP_KEEP) {
        return Screen::getInstance()->isKeepScreenCapture();
    } else {
        CONFIG_MAP::const_iterator iter = mMapConfig.find(key);
        if (iter != mMapConfig.cend()) {
            return iter->second.bVal;
        }
    }

    return def;
}

void XMod::setConfig_Bool(const std::string &key, bool value) {
    if (key == SCREENCAP_KEEP) {
        Screen::getInstance()->keep(value);
    }
}

int XMod::getConfig_Int(const std::string &key, int def) {
    if (key == EXPECTED_ORIENTATION) {
        return Screen::getInstance()->getOrientation();
    } else {
        CONFIG_MAP::const_iterator iter = mMapConfig.find(key);
        if (iter != mMapConfig.cend()) {
            return iter->second.nVal;
        }
    }

    return def;
}

void XMod::setConfig_Int(const std::string &key, int value) {
    if (key == EXPECTED_ORIENTATION) {
        Screen::getInstance()->init(value);
    } else if (key == SCREENCAP_POLICY) {
        mMapConfig[key].nVal = value;
    }
}

std::string XMod::getConfig_String(const std::string &key, const std::string &def) {
    CONFIG_MAP::const_iterator iter = mMapConfig.find(key);
    if (iter != mMapConfig.cend()) {
        return iter->second.szVal;
    }
    return def;
}

void XMod::setConfig_String(const std::string &key, const std::string &value) {
//    strncpy(mMapConfig[key].szVal, value.c_str(), STRING_PROPERTY_LEN - 1);
//    mMapConfig[key].szVal[STRING_PROPERTY_LEN - 1] = '\0';
}

std::string XMod::getPublicPath() {
    return "/sdcard/CodeLua/public";
}

std::string XMod::getPrivatePath() {
    return "/sdcard/CodeLua/private/1000";
}

std::string XMod::resolvePath(const std::string &path) {

#define PUBLIC_PREFIX "[public]"
#define PRIVATE_PREFIX "[private]"

    std::string new_path = path;
    int pos = new_path.find(PUBLIC_PREFIX);
    if (pos == 0) {
        new_path.replace(0, strlen(PUBLIC_PREFIX), getPublicPath() + "/");
    } else {
        pos = new_path.find(PRIVATE_PREFIX);
        if (pos == 0) {
            new_path.replace(0, strlen(PRIVATE_PREFIX), getPrivatePath() + "/");
        }
    }
    return new_path;
}

void XMod::setOnEventCallback(int event, int funID) {
    removeOnEventCallback(event);
    if (funID != 0) {
        mMapEvent[event] = funID;
    }
}

void XMod::executeEvent_OnUserExit() {
    lua_State *L = LuaJavaHelper::getInstance()->getLuaState();
    if (!L) {
        return;
    }

    int funID = findEventCallbackFunID(EVENT_ON_USER_EXIT);
    if (funID != 0) {
        toluahelper_get_function_by_refid(L, funID);
        if (lua_isfunction(L, -1)) {
            lua_pcall(L, 0, 0, 0);
        }
    }
}

void XMod::executeEvent_OnRuntimeError(const std::string &errMsg) {
    lua_State *L = LuaJavaHelper::getInstance()->getLuaState();
    if (!L) {
        return;
    }

    int funID = findEventCallbackFunID(EVENT_ON_RUNTIME_ERROR);
    if (funID != 0) {
        toluahelper_get_function_by_refid(L, funID);
        if (lua_isfunction(L, -1)) {
            lua_pushstring(L, errMsg.c_str());
            lua_pcall(L, 1, 0, 0);
        }
    }
}

void XMod::removeOnEventCallback(int event) {
    lua_State *L = LuaJavaHelper::getInstance()->getLuaState();
    if (!L) {
        return;
    }

    int funID = findEventCallbackFunID(event);
    if (funID != 0) {
        toluahelper_remove_function_by_refid(L, funID);
        mMapEvent.erase(event);
    }
}

void XMod::removeAllOnEventCallback() {
    lua_State *L = LuaJavaHelper::getInstance()->getLuaState();
    if (!L) {
        return;
    }

    std::for_each(mMapEvent.cbegin(), mMapEvent.cend(), [L](const auto &v) {
        int funID = v.second;
        toluahelper_remove_function_by_refid(L, funID);
    });
    mMapEvent.clear();
}

int XMod::findEventCallbackFunID(int event) {
    int funID = 0;
    const auto &iter = mMapEvent.find(event);
    if (iter != mMapEvent.cend()) {
        funID = iter->second;
    }
    return funID;
}

void XMod::exit() {
    LuaJavaHelper::getInstance()->stop();
}

void XMod::restart() {

}